package com.ouyunc.gateway.config.oauth;


import com.ouyunc.cache.redis.RedisFactory;
import com.ouyunc.common.constant.PermitAllUrl;
import com.ouyunc.gateway.config.oauth.override.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.DelegatingReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;

import java.util.LinkedList;

/**
 * @Author fangzhenxun
 * @Description webflux 的spring security 资源服务配置
 **/
@EnableWebFluxSecurity
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {



    /**
     * 权限管理器
     */
    @Autowired
    private IReactiveAuthenticationManager iReactiveAuthenticationManager;

    /**
     * 权限管理器
     */
    @Autowired
    private IReactiveAuthorizationManager iReactiveAuthorizationManager;


    /**
     * token 转换器，转成Authentication
     */
    @Autowired
    private IServerAuthenticationConverter iServerAuthenticationConverter;


    /**
     * 认证失败处理器
     */
    @Autowired
    private IServerAuthenticationEntryPoint iServerAuthenticationEntryPoint;


    /**
     * 鉴权失败处理器
     */
    @Autowired
    private IServerAccessDeniedHandler iServerAccessDeniedHandler;



    /**
     * @param
     * @return org.springframework.security.oauth2.provider.token.TokenStore
     * @Author fangzhenxun
     * @Description 配置token的存储方式
     */
    @Bean
    public TokenStore tokenStore() {
        RedisTokenStore redisTokenStore = new RedisTokenStore(RedisFactory.redisTemplate().getConnectionFactory());
        // 注意: 这里配置的redis 前缀一定要与授权中心的前缀保持一致，否则取不到值
        redisTokenStore.setPrefix("oauth2-token:");
        return redisTokenStore;
    }


    /**
     * 用户信息验证管理器，可按需求添加多个按顺序执行
     */
    public ReactiveAuthenticationManager reactiveAuthenticationManager() {
        LinkedList<ReactiveAuthenticationManager> managers = new LinkedList<>();
        managers.add(iReactiveAuthenticationManager);
        return new DelegatingReactiveAuthenticationManager(managers);
    }


    /**
     * @param http
     * @return org.springframework.security.web.server.SecurityWebFilterChain
     * @Author fangzhenxun
     * @Description aouth2 的过滤器
     */
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) throws Exception {
        // 配置资源服务器
        return http.oauth2ResourceServer()
                .authenticationManagerResolver( request -> Mono.just(reactiveAuthenticationManager()))
                .bearerTokenConverter(iServerAuthenticationConverter)
                // 鉴权失败
                .accessDeniedHandler(iServerAccessDeniedHandler)
                // 认证失败
                .authenticationEntryPoint(iServerAuthenticationEntryPoint)
                .and()
                .authorizeExchange()
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                // 放行swagger2 的请求
                .pathMatchers(PermitAllUrl.permitAllUrl(false)).permitAll()
                .anyExchange().access(iReactiveAuthorizationManager)
                .and()
                //关闭CSRF（Cross-site request forgery）跨站请求伪造
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .logout().disable()
                .build();
    }




}
